const path = require('path') // node.js的路径模块
const ESLintPlugin = require('eslint-webpack-plugin') // eslint插件
const HtmlWebpackPlugin = require('html-webpack-plugin') // html插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 抽离css成单独文件插件
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin') // css压缩插件
const TerserWebpackPlugin = require('terser-webpack-plugin') // 压缩js的插件
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin') // 图片压缩插件
const PreloadWebpackPlugin = require('@vue/preload-webpack-plugin') // js预处理插件
const WorkboxPlugin = require('workbox-webpack-plugin') // 项目PWA离线处理插件
const os = require('os')
const threads = os.cpus().length // 获取CPU的核数

module.exports = {
  // 输入
  entry: './src/main.js', // 相对路径
  // entry: { // 多入口
  //   app: './src/app.js',
  //   main: './src/main.js'
  // },
  // 输出
  output: {
    path: path.resolve(__dirname, 'dist'), // 绝对路径，__dirname表示当前位置
    filename: '[name].js', // 多入口输出文件命名
    chunkFilename: 'js/[name].chunk.js', // 给打包输出的其他文件命名，例如动态语法通过注释配置的名称
    clean: true, // 自动清空上次打包的内容。
  },
  module: {
    // 加载器
    rules: [
      {
        oneOf: [
          // 处理css资源
          {
            test: /\.css$/,
            use: [ // 执行顺序：从右向左（从下向上）
              MiniCssExtractPlugin.loader, // 提取css成单独文件
              'css-loader', // 将css资源编译成commonjs的模块到js中
              {
                loader: 'postcss-loader', // 兼容性处理
                options: {
                  postcssOptions: {
                    plugins: [
                      'postcss-preset-env', // 能解决大多数样式兼容新问题
                    ]
                  }
                }
              },
            ]
          },
          // 处理less资源
          {
            test: /\.less$/,
            use: [ // 执行顺序：从右向左（从下向上）
              MiniCssExtractPlugin.loader, // 提取css成单独文件
              'css-loader', // 将css资源编译成commonjs的模块到js中
              {
                loader: 'postcss-loader', // 兼容性处理
                options: {
                  postcssOptions: {
                    plugins: [
                      'postcss-preset-env', // 能解决大多数样式兼容新问题
                    ]
                  }
                }
              },
              'less-loader', // 将less编译成css文件
            ]
          },
          // 处理sass资源
          {
            test: /\.s[ac]ss$/,
            use: [ // 执行顺序：从右向左（从下向上）
              MiniCssExtractPlugin.loader, // 提取css成单独文件
              'css-loader', // 将css资源编译成commonjs的模块到js中
              {
                loader: 'postcss-loader', // 兼容性处理
                options: {
                  postcssOptions: {
                    plugins: [
                      'postcss-preset-env', // 能解决大多数样式兼容新问题
                    ]
                  }
                }
              },
              'sass-loader', // 将sass编译成css文件
            ]
          },
          // 处理stylus资源
          {
            test: /\.styl$/,
            use: [ // 执行顺序：从右向左（从下向上）
              MiniCssExtractPlugin.loader, // 提取css成单独文件
              'css-loader', // 将css资源编译成commonjs的模块到js中
              {
                loader: 'postcss-loader', // 兼容性处理
                options: {
                  postcssOptions: {
                    plugins: [
                      'postcss-preset-env', // 能解决大多数样式兼容新问题
                    ]
                  }
                }
              },
              'stylus-loader', // 将stylus编译成css文件
            ]
          },
          // 处理图片资源
          {
            test: /\.(png|jpe?g|gif|webp|svg)$/,
            type: 'asset',
            parser: {
              dataUrlCondition: {
                // 小于10kb的图片转成base64
                // 优点：减少请求数量；缺点：体积会变大；
                maxSize: 10 * 1024, // 10kb
              },
              generator: {
                // 输出资源名称配置
                filename: 'images/[hash:10][ext][query]'
              }
            }
          },
          // 处理字体图标资源
          {
            test: /\.(ttf|woff2?)$/,
            type: 'asset/resource', // 类似于webpack4的file-loader
            parser: {
              generator: {
                // 输出资源名称配置
                filename: 'fonts/[hash:10][ext][query]'
              }
            }
          },
          // 处理其他资源
          {
            test: /\.(mp3|mp4|avi)$/,
            type: 'asset/resource', // 类似于webpack4的file-loader
            parser: {
              generator: {
                // 输出资源名称配置
                filename: 'media/[hash:10][ext][query]'
              }
            }
          },
          // 处理js资源
          {
            test: /\.js$/,
            exclude: /node_modules/, // exclude 和 include 只用一种
            // include: path.resolve(__dirname, 'src'),
            use: [
              {
                loader: 'thread-loader', // 开启多进程
                options: {
                  works: threads,
                }
              },
              {
                loader: 'babel-loader',
                options: {
                  cacheDirectory: true, // 开启babel缓存
                  cacheCompression: false, // 关闭缓存文件压缩
                  plugins: ['@babel/plugin-transform-runtime'], // 避免重复引入辅助代码，导致体积过大
                }
              }
            ]
          }
        ]
      }
    ]
  },
  // 插件
  plugins: [
    new ESLintPlugin({
      context: path.resolve(__dirname, 'src'),  // 检测src目录下的文件
      exclude: 'node_modules', // 默认值
      cache: true, // 开启缓存
      cacheLocation: path.resolve(__dirname, 'node_modules/.cache/eslintCache'), // 指定缓存目录
    }),
    // 处理html资源
    new HtmlWebpackPlugin({
      // 以public/index.html文件作为模板文件生成新的文件
      template: path.resolve(__dirname, 'public/index.html')
    }),
    // 抽离css成单独文件
    new MiniCssExtractPlugin({
      filename: 'css/[name].chunk.css',
      chunkFilename: 'css/[name].chunk.css', // 给打包输出的动态样式文件命名
    }),
    // 处理css压缩
    new CssMinimizerWebpackPlugin(),
    // js压缩
    new TerserWebpackPlugin({
      parallel: threads, // 开启多进程和设置进程数量
    }),
    // 压缩图片
    new ImageMinimizerPlugin({
      minimizer: {
        implementation: ImageMinimizerPlugin.imageminGenerate,
        options: {
          plugins: [
            ['gifsicle', {interlaced: true}],
            ['jpegtran', {progressive: true}],
            ['optipng', {optimizationLevel: 5}],
            ['svgo', {
              plugins: [
                'preset-default',
                'prefixIds',
                {
                  name: 'sortAttrs',
                  params: {
                    xmlnsOrder: 'alphabetical'
                  }
                }
              ]
            }]
          ]
        }
      }
    }),
    // js预加载处理
    new PreloadWebpackPlugin({
      rel: 'preload',
      as: 'script',
      // rel: 'prefetch'
    }),
    // 项目PWA处理，打包完成会输出一个service-work.js文件
    new WorkboxPlugin({
      // 这些选项帮助快速启用 ServiceWorkers
      // 不允许遗留任何“旧的” ServiceWorkers
      clientsClaim: true,
      skipWaiting: true,
    })
  ],
  optimization: {
    // 代码分割配置
    splitChunks: {
      chunks: 'all', // 对所有模块进行分割，例如动态导入语法，import(/* webpackChunkName:math*/ './math.js')
    }
  },
  // 模式
  mode: 'production',
  devtool: 'source-map'
}
